package com.simp.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.simp.costant.Constant;
import com.simp.dto.SysLogDto;
import com.simp.entity.SysLogEntity;
import com.simp.entity.SysUserEntity;
import com.simp.mapper.SysLogMapper;
import com.simp.page.PageVO;
import com.simp.page.R;
import com.simp.utils.ExceptionUtils;
import com.simp.utils.IPUtils;
import com.simp.utils.JwtUtil;
import com.simp.vo.TokenInfoVo;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author pan.shun
 * @since 2022/3/16 20:15
 */
@Slf4j
@Service
public class SysLogService extends ServiceImpl<SysLogMapper, SysLogEntity> {

    @Autowired
    private SysUserService sysUserService;

    public PageVO<SysLogEntity> getPageList(SysLogDto sysLogDto) {
        LambdaQueryWrapper<SysLogEntity> queryWrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(sysLogDto.getUserName())) {
            queryWrapper.like(SysLogEntity::getUserName, sysLogDto.getUserName());
        }
        if (null != sysLogDto.getStatus()) {
            queryWrapper.eq(SysLogEntity::getStatus, sysLogDto.getStatus());
        }
        if (null != sysLogDto.getStartTime()) {
            queryWrapper.gt(SysLogEntity::getCreateTime, new Date(sysLogDto.getStartTime()));
        }
        if (null != sysLogDto.getEndTime()) {
            queryWrapper.lt(SysLogEntity::getCreateTime, new Date(sysLogDto.getEndTime()));
        }
        queryWrapper.orderByDesc(SysLogEntity::getCreateTime);

        Page<SysLogEntity> page = this.page(new Page<>(sysLogDto.getCurrent(), sysLogDto.getSize()), queryWrapper);

        List<SysLogEntity> records = page.getRecords();
        records.forEach(r -> {
            if (r.getEventContent() == null) {
                r.setEventContent(getEvent(r.getActionEvent()));
            }
        });
        return new PageVO<>(page);
    }

    private String getEvent(Integer event) {
        if (event == null) {
            return "异常";
        }
        if (event.equals(Constant.LOG_EVENT.LOGIN)) {
            return "登录";
        } else if (event.equals(Constant.LOG_EVENT.LOGIN_OUT)) {
            return "退出";
        } else if (event.equals(Constant.LOG_EVENT.USER_FORBIDDEN)) {
            return "账户冻结";
        } else if (event.equals(Constant.LOG_EVENT.USER_AUDIT)) {
            return "账户审核";
        } else if (event.equals(Constant.LOG_EVENT.PASSWORD_ERROR)) {
            return "密码错误";
        } else {
            return "未知操作";
        }
    }

    /**
     * 日志保存
     */
    public void saveSysLog(HttpServletRequest request, String userName, String userId, Integer status, Float elapsedTime, Integer event) {
        SysLogEntity sysLogEntity = new SysLogEntity();
        try {
            String token = "";
            String header = request.getHeader(Constant.TOKEN_CONFIG.TOKEN_KEY);
            if (!StringUtils.isEmpty(header)) {
                token = header;
            }
            if (StringUtils.isEmpty(header)) {
                String parameter = request.getParameter(Constant.TOKEN_CONFIG.TOKEN_KEY);
                if (!StringUtils.isEmpty(parameter)) {
                    token = parameter;
                }
            }
            if (!StringUtils.isEmpty(token) && !"null".equals(token)) {
                TokenInfoVo jwtClaimsDetail = JwtUtil.getJwtClaimsDetail(token);
                userName = jwtClaimsDetail.getUserName();
                userId = jwtClaimsDetail.getUserId();
            }
            String agentStr = request.getHeader("User-Agent");

            if (StringUtils.isEmpty(agentStr)) {
                agentStr = request.getHeader("user-agent");
                log.info("获取到当前客户端代理信息 user-agent 为:{}", agentStr);
            }
            if (!StringUtils.isEmpty(agentStr)) {
                UserAgent agent = UserAgent.parseUserAgentString(agentStr);
                sysLogEntity.setBrowserName(agent.getBrowser().getName());
                sysLogEntity.setDeviceName(agent.getOperatingSystem().getName());
                agentStr = org.apache.commons.lang3.StringUtils.substring(agentStr, 0, 255);
                sysLogEntity.setUserAgent(agentStr);
            }

            sysLogEntity.setUserId(userId);
            sysLogEntity.setUserName(userName);
            sysLogEntity.setIpAddress(IPUtils.getIp(request));
            sysLogEntity.setElapsedTime(elapsedTime != null ? elapsedTime : 0);
            sysLogEntity.setActionEvent(event);

            String path = request.getRequestURI();
            String contextPath = request.getContextPath();
            if (!StringUtils.isEmpty(contextPath) && path.startsWith(contextPath)) {
                path = path.substring(contextPath.length());
            }
            sysLogEntity.setRequestUri(path);
            sysLogEntity.setStatus(status);
            log.info("日志记录完毕 ，{}", JSON.toJSONString(sysLogEntity));
        } catch (Exception e) {
            sysLogEntity.setActionEvent(Constant.LOG_EVENT.ERROR);
            sysLogEntity.setStatus(Constant.LOG_STATUS.FAIL);
            sysLogEntity.setException(ExceptionUtils.print(e));
        } finally {
            this.save(sysLogEntity);
        }

    }

    @Async
    public void saveAspectLog(SysLogEntity sysLogEntity, Long startTime) {
        long endTime = System.currentTimeMillis();
        sysLogEntity.setElapsedTime((float) (endTime - startTime) / 1000);
        this.save(sysLogEntity);
    }

    public R getHomeLog() {
        Map<String, String> userHeadMap = new HashMap<>();
        List<SysUserEntity> userList = sysUserService.list();
        userList.forEach(r -> {
            if (!StringUtils.isEmpty(r.getUserHead())) {
                userHeadMap.put(r.getUserName(), r.getUserHead());
            }
        });
        LambdaQueryWrapper<SysLogEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysLogEntity::getStatus, Constant.LOG_STATUS.SUCCESS);
        queryWrapper.orderByDesc(SysLogEntity::getCreateTime).last("limit 0,10");
        List<SysLogEntity> list = this.list(queryWrapper);
        list.forEach(r -> {
            if (r.getEventContent() == null) {
                r.setEventContent(getEvent(r.getActionEvent()));
            }
            if (userHeadMap.containsKey(r.getUserName())) {
                r.setUserHead(userHeadMap.get(r.getUserName()));
            }
        });
        return R.success(list);
    }
}
